package com.example.springsecurity.service;

import com.example.springsecurity.mapper.UserMapper;
import com.example.springsecurity.pojo.LoginVO;
import com.example.springsecurity.pojo.MyUser;
import com.example.springsecurity.pojo.MyUserDetails;
import com.example.springsecurity.pojo.Result;
import com.example.springsecurity.utils.JwtUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Resource
    private AuthenticationManager authenticationManager;//实际返回的是自定义的 ProviderManager(配置类中配置)
    @Resource
    private UserMapper userMapper;
    @Override
    public Result login(LoginVO loginVO) {
        String username = loginVO.getUsername();
        String password = loginVO.getPassword();


        String captcha = loginVO.getCaptcha();//验证码
        Object code = redisTemplate.opsForValue().get("code");
        if (code == null) {
            return new Result(401,"验证码已过期或未生成",null);
        }

        //封装到一个待认证的unauthenticated对象中
        //UsernamePasswordAuthenticationToken是authentication接口的实现类
        UsernamePasswordAuthenticationToken unauthenticated = UsernamePasswordAuthenticationToken.unauthenticated(username, password);

        try {

            Authentication authentication = authenticationManager.authenticate(unauthenticated);//这句很容易报错
            //未认证体中的username和password是用户输入的，authenticationManager会调用service进而mapper，从数据库中获取出加密后的密码，
            //并通过内置的BCryptPasswordEncoder(默认)把用户输入的密码加密，然后与数据库中的密码进行比较，如果相等，则认证成功


            //认证成功后，返回的authentication对象其他内容均有，但credentials(即密码)为null
            //后续的请求中，应用程序仅使用 Authentication 对象中的用户身份信息和权限进行授权控制，而无需再次验证凭证。
            if (authentication.isAuthenticated()) {
                //登录成功
                //1.把authentication存入安全上下文SecurityContextHolder中，后续供其他过滤器使用
                SecurityContextHolder.getContext().setAuthentication(authentication);
                //2.生成一个token
                HashMap<String, Object> map = new HashMap<>();
                MyUserDetails myUserDetails = (MyUserDetails) authentication.getPrincipal();
                MyUser myUser = myUserDetails.getMyUser();
                map.put("userId", myUser.getUserId());
                String token = JwtUtil.genToken(map);
                //3.将token存入redis中

                ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
                operations.set(token, token, 1, TimeUnit.HOURS);//redis中的token过期时间与token一致
                //4.返回token给前端
                return Result.success(token);
            }
        } catch (AuthenticationException e) {
            return Result.error("用户名或密码错误");
        }

        return Result.error("登录失败!");
    }
}
